local skynet = require "skynet"
local log = require "sky_log"
local def = require "srv_define"
local skynet_db_tool = require "skynet_db_tool"
local logic = require "game_logic"

local game_process = {}

local LocalGame = {}
local TableLogic = require "game_logic"
local robot = require "robot"
--------------------------------LocalGame-------------------------------

local game_process = {}
local TEST_OPEN = true

function game_process.test3()
    log.info("22222222222222222222")
    skynet.error("11111111111111111111111")
end

--本文所有变量汇总 
function LocalGame.DataInit()
    --初始化一次即可的数据
    LocalGame.roomSrv = nil
    LocalGame.tableId = nil
    LocalGame.gameType = nil    
    LocalGame.roomId = nil              --房间号
    LocalGame.roomDiZhu = nil           --底注
    LocalGame.roomLevel = nil
    LocalGame.roomCode = nil
    LocalGame.reConTime = nil
    LocalGame.taxRate = 0               --系统税
    LocalGame.curState = nil            --游戏状态
    LocalGame.robotCarry = {}           --机器人携带
    LocalGame.handle = nil
    LocalGame.isRunning = nil
    LocalGame.xpcallStatus = true
    --
    LocalGame.player_num = 0
    LocalGame.bankuser = nil

    --local local_name = skynet.getenv("local_name")
    --LocalGame.manager = ".game_"..local_name
    LocalGame.packId = 225
end

--每局数据复位
function LocalGame.DataReset(args)
    LocalGame.startTime = os.time()  
    LocalGame.checkTime = 0
    LocalGame.curState = def.state.gameStart
    LocalGame.reConTime = os.time() + def.stateTime[LocalGame.curState]
    LocalGame.canQuit = false
    LocalGame.seatList = {}
    LocalGame.playerList = {}
    --
    LocalGame.theTurnPlayers = {}       --每回合需要操作的玩家表
    LocalGame.lastOutCard = def.maxValue
    LocalGame.lastOutCardUser = def.maxValue
    LocalGame.leftCards = TableLogic.GetLeftCardNum()
    LocalGame.isNowBuhua = false
    --每局牌局记录
    LocalGame.paiju = {}


    --游戏开始平台直接发来座位上的玩家数据了
    --log.info("DataReset args.player_list=", args.player_list)
    local insertNums = 0
    for _, user in pairs(args.player_list) do
        --通用user属性
        local insertUser = {}
        insertUser.agentFd = user.agent
        insertUser.username = user.username
        insertUser.headimg_id = user.headimg_id
        insertUser.sex = user.sex
        insertUser.gold = user.gold
        insertUser.player_id = user.player_id
        insertUser.isRobot = user.is_robot or false
        insertUser.seat_id = user.seat_id 
        insertUser.score = 0              --输赢分数
        insertUser.tax = 0
        insertUser.taxScore = 0           --税后金币
        insertUser.gangFen = 0            --杠分
        insertUser.jinPai = {}            --开局手牌
        insertUser.handCards = {}         --玩家手牌
        insertUser.outCards = {}          --打的牌
        insertUser.getCards = {}          --摸的牌
        insertUser.huaPai = {}
        insertUser.fanxing = {}           --番型
        insertUser.fanxingValue = {}      --番型倍数(下标和上面番型对应)
        for _, v in ipairs(def.cards) do
            insertUser.handCards[v] = 0
        end
        insertUser.cardsCombo = {}        --玩家吃碰杠数据
        insertUser.action = {}            --玩家可操作动作（操作后清掉)
        insertUser.huInfo = {             --一局胡信息
            isHu = false,
            oneHuInfo = {
                dianPaoRen = def.maxValue,
                huCard = def.maxValue,
            }
        }
        insertUser.isTing = def.tingStatus.nothing             
        insertUser.tingCards = {}              --正在听的牌
        insertUser.canTingCards = {}           --当点击听按钮时，所有可以听的牌。若超时或断线时，客户端未选择就会在这里面随机一个
        insertUser.tingInfo = {}

        --一些牵扯代码结构多，放此处全局调用的变量
        insertUser.isTianTing = false          --玩家是否天听
        insertUser.isGang = false              --该轮是否杠，轮到自己时复位

        LocalGame.seatList[user.seat_id] = insertUser
        LocalGame.playerList[user.player_id] = insertUser
        insertNums = insertNums + 1
    end

    log.debug("LocalGame.seatList=", LocalGame.seatList)
    log.debug("LocalGame.playerList=", LocalGame.playerList)
    --判断人数
    if args.player_num~=insertNums then 
        --log.error('args.player_num = ',args.player_num,'  insertNums = ',insertNums)
        LocalGame.canQuit = true
        return
    end
    LocalGame.player_num = args.player_num
    --记录真人胡的牌，追杀模式下不给他这张牌
    LocalGame.playerHuCards = {}    

    --
    robot.init(LocalGame.player_num, LocalGame.roomConfig.room_base_note, LocalGame.controlMode)
end

function LocalGame.FillPlayerList()
    local playerList = {}
    for _, v in pairs(LocalGame.seatList) do
        local info = {}
        info.player_id = v.player_id
        info.seat_id = v.seat_id
        info.username = v.username
        info.headimg_id = v.headimg_id
        info.sex = v.sex
        info.score = tostring(v.score)
        info.gold = tostring(v.gold)
        table.insert(playerList, info)
    end

    return playerList
end

--游戏开始
function LocalGame.GameStart(args)
    TableLogic.Init(LocalGame.controlMode)
    LocalGame.DataReset(args)
    --
    robot.game_start(LocalGame.seatList)
    
    --游戏开始组播开始消息
    local startNotify = {
        room_info = {room_base_note=tostring(LocalGame.roomDiZhu), room_code=LocalGame.roomCode},
        time_out = def.stateTime[LocalGame.curState],         
        player_list = LocalGame.FillPlayerList()
    }
    log.info("startNotify=", startNotify)
    LocalGame.broadcast_message({ game_start_notify = startNotify })

    --游戏开始延时N秒动画后发送庄家
    skynet.timeout(def.stateTime[LocalGame.curState]*100, function()
        LocalGame.curState = def.state.sendBanker
        LocalGame.DispatchBanker()
    end)
end

function LocalGame.SendPlayerPos()
    for _, v in pairs(LocalGame.seatList) do
        if v.seat_id==LocalGame.bankuser then 
            v.pos = def.pos.east
        else
            v.pos = def.pos.west
        end
    end
end

--发送庄家
function LocalGame.DispatchBanker()
    if LocalGame.bankuser==nil then 
        LocalGame.bankuser = LocalGame.seatList[1].seat_id
    else 
        LocalGame.bankuser = LocalGame.bankuser + 1
        if LocalGame.bankuser>#LocalGame.seatList then 
            LocalGame.bankuser = LocalGame.seatList[1].seat_id
        end
    end

    --[[庄家测试用
    for _, v in pairs(LocalGame.seatList) do
        if v.isRobot==true then 
            LocalGame.bankuser = v.seat_id
        end
    end
    --]]

    --根据庄位分座位号
    LocalGame.SendPlayerPos()

    local notify = {}
    for _, v in pairs(LocalGame.seatList) do
        local notify = {}
        notify.bankUser_seat_id = LocalGame.bankuser
        notify.windPos = v.pos
        log.info("DispatchBankerNotify=", notify)
        LocalGame.sendclient_message(v.player_id, { send_bank_notify = notify } )
    end
    
    --定庄后延时N秒动画后发牌
    skynet.timeout(def.stateTime[LocalGame.curState]*100, function()
        LocalGame.curState = def.state.sendCards
        LocalGame.GamestartSendCards()
    end)
end

--游戏开始的发牌
function LocalGame.GamestartSendCards()
    TableLogic.RandCards()

    --配牌，给配牌玩家第一个把牌先发了
    local testPlayerId 
    local hasPeiPai 
    for _, v in pairs(LocalGame.seatList) do
        local isPei = TableLogic.SendTestCards(TEST_OPEN, v.player_id)
        if isPei==true then 
            hasPeiPai = v.seat_id
            local pai = TableLogic.GetCardX(def.fapaiNum)
            for _, card in pairs(pai) do
                v.handCards[card] = v.handCards[card] + 1
            end
            v.jinPai = LocalGame.SortCards(TableLogic.IndexToCard(v.handCards))
        end
    end

    --[[
    local robotCards = {
        11, 11, 11,
        12, 12, 12,
        13, 13, 13,
        15, 16, 42,
        42
    }
    --给机器人发牌
    TableLogic.ChangeCards( robotCards )
    --]]

    --LocalGame.leftCards = LocalGame.leftCards - 13*#LocalGame.seatList
    --每个人先发13张牌
    for _, v in pairs (LocalGame.seatList) do
        if hasPeiPai~=v.seat_id then 
            local pai = TableLogic.GetCardX(def.fapaiNum)
            for _, card in pairs(pai) do
                v.handCards[card] = v.handCards[card] + 1
            end
            v.jinPai = LocalGame.SortCards(TableLogic.IndexToCard(v.handCards))
        end
    end

    LocalGame.leftCards = TableLogic.GetLeftCardNum()
    for _, v in pairs (LocalGame.seatList) do
        local sendCards = TableLogic.IndexToCard(v.handCards)
        local notify = {
            seat_id = v.seat_id - 1,
            cards = sendCards,
            left_card = LocalGame.leftCards,
        }
        log.info("GamestartSendCards=", notify)
        LocalGame.sendclient_message(v.player_id, { send_cards_notify = notify } )
    end

    --玩家补花
    LocalGame.GameStartBuHua()

    for _, v in pairs(LocalGame.seatList) do
        if v.isRobot==false and LocalGame.controlMode==-1 then
            LocalGame.playerHuCards = TableLogic.OutCardCheckTing(v.handCards)
        end
    end

    log.info("------------------Gaming-----------------")
    ---[[
    --发牌后延时N秒动画后游戏正式从第一位玩家开始
    skynet.timeout(def.stateTime[LocalGame.curState]*100, function()
        --光标从第一位操作者（庄家）开始
        LocalGame.curState = def.state.gaming
        LocalGame.curPlayer = LocalGame.bankuser
        LocalGame.TurnOper(true, {LocalGame.curPlayer})    
    end)
    --]]
end
 
function LocalGame.GameStartBuHua()
    --游戏开始前的补花需要延时
    skynet.sleep(100)
    log.info("------------------BuHua-----------------")
    --玩家补花操作
    for k, v in pairs(LocalGame.seatList) do
        local hua_cards = {}
        for cardValue, cardNum in pairs(v.handCards) do
            if cardValue>=51 then 
                for i=1, cardNum do
                    table.insert(hua_cards, cardValue)
                end
            end
        end
        if #hua_cards>0 then 
            --log.info("k=", k)
            LocalGame.PlayerBuHua(k, hua_cards, true)
            --每位玩家0.5秒补花，且游戏开始的补花不会再补到花牌
            skynet.sleep(50)
        end
    end
end

--得到本次轮到的玩家
function LocalGame.GetCurPlayer(turnSeats)
    if LocalGame.curPlayer==nil then 
        LocalGame.curPlayer = LocalGame.bankuser
    else
        LocalGame.curPlayer = LocalGame.curPlayer%def.maxPlayer + 1
        if turnSeats~=nil then 
            --预留一炮多响等多响应操作
            LocalGame.curPlayer = turnSeats[1]
        end
        
    end
end

--每个操作回合复位数据
function LocalGame.EveryTurnReset(notResetTimer)
    LocalGame.theTurnPlayers = {}
    if notResetTimer~=true then
        LocalGame.checkTime = 0
    end
    for _, v in pairs(LocalGame.seatList) do
        v.action = {}
    end
end

--轮到玩家摸牌打牌操作， isNeedGetCard[true要摸牌] turnSeats[若有值则转到该椅子]
function LocalGame.TurnOper(isNeedGetCard, turnSeats)
    local player = LocalGame.seatList[LocalGame.curPlayer]
    if not player then 
        log.debug("LocalGame.curPlayer=", LocalGame.curPlayer)
        log.debug("LocalGame.seatList=", LocalGame.seatList)
        return
    end  

    log.debug("LocalGame.curPlayer=", LocalGame.curPlayer)
    --先算出本次轮到玩家
    LocalGame.GetCurPlayer(turnSeats)
   
    --复位玩家是否杠了的操作
    player.isGang = false

    local turnNotify = {}
    turnNotify.seat_id = LocalGame.curPlayer
    turnNotify.time_out = def.stateTime[LocalGame.curState]
    log.info("turn_oper_notify= ", turnNotify)
    LocalGame.broadcast_message({ turn_oper_notify = turnNotify } )

    --轮到操作后需要摸牌时
    if isNeedGetCard==true then
        LocalGame.GetCard()
    end
end

--玩家补花
function LocalGame.PlayerBuHua(seatId, huaCards, noHua)
    local player = LocalGame.seatList[seatId]
    if not player then 
        return
    end  

    --手里花牌减掉
    for _, v in pairs(huaCards) do
        if player.handCards[v] > 0 then 
            player.handCards[v] = player.handCards[v] - 1
        end
        table.insert(player.huaPai, v)
    end

    local notify = {
        seat_id = seatId,
        hua_card = huaCards,
        status = 0,
    }
    if noHua==true then 
        notify.status = 1
    end
    log.info("-------------sendBuHua =", notify)
    LocalGame.broadcast_message({ send_huapai_notify = notify } ) 
    
    LocalGame.GetCard(#huaCards, noHua, seatId)

    --补花标志位，补花期间不能出牌，否则逻辑错误
    LocalGame.isNowBuhua = false
end

--玩家摸牌    n张数，noHua[true代表不摸花牌]
function LocalGame.GetCard(n, noHua, seatId)
    if n==nil then 
        n = 1
    end
    if seatId==nil then 
        seatId = LocalGame.curPlayer
    end

    local player = LocalGame.seatList[seatId]
    if not player then 
        return
    end  

    --回收模式真人不摸胡的牌
    local huCards = {}
    local getNouseful = false
    local robotGetCards = {}
    if LocalGame.controlMode==-1 then 
        if player.isRobot==false then 
            huCards = LocalGame.playerHuCards
            getNouseful = true
        else
            local n = math.random(1, 10) 
            if n<=4 then 
                robotGetCards = TableLogic.OutCardCheckTing(player.handCards)
            end
        end
    end
    --赠送模式玩家赢钱
    if LocalGame.controlMode==1 then 
        if player.isRobot==false then 
            robotGetCards = TableLogic.OutCardCheckTing(player.handCards)
        end
    end

    --牌减
    LocalGame.leftCards = LocalGame.leftCards - n
    local getCards = TableLogic.GetCardX(n, noHua, huCards, player.handCards, getNouseful, robotGetCards)
    --牌摸完了
    if #getCards<n then 
        LocalGame.curState = def.state.finish
        LocalGame.Finish(0)
        return
    end

    --只记录玩家正常游戏中摸1张牌的那张牌
    if n==1 then 
        table.insert(player.getCards, getCards[1])
    end

    --摸牌消息组播
    local notify = {
        seat_id = seatId,
        left_card = LocalGame.leftCards, 
    }
    --emptyCards是指给摸牌那个人发牌
    local emptyCards = {}
    for _, v in pairs(getCards) do
        table.insert(emptyCards, def.maxValue)
    end
    for _, v in pairs(LocalGame.seatList) do 
        if v.seat_id==seatId then 
            notify.card = getCards
        else
            notify.card = emptyCards
        end
        LocalGame.sendclient_message(v.player_id, { get_card_notify = notify } )
    end 
    log.info("get_card_notify=", getCards)

    --摸到花牌发送补花消息
    if getCards[1]>=51 then
        LocalGame.isNowBuhua = true
        skynet.timeout(50, function()
            LocalGame.PlayerBuHua(seatId, getCards)
            LocalGame.checkTime = 0
        end)
        return
    end

    --玩家手里该牌+1
    for _, v in pairs(getCards) do
        player.handCards[v] = player.handCards[v] + 1
    end

    --只有开始游戏的补花不再重复摸花，此时是所有玩家补一次，所以不进入下面手牌检测
    if noHua==true then 
        return
    end

    --摸牌检测前和打牌操作后操作数据服务
    LocalGame.EveryTurnReset()

    --[[
    --策划要听牌时能杠能自摸，那就直接摸牌检测就行了，不用判断了
    if #player.tingCards==0 then 
        --检测他是否听牌
        LocalGame.CheckTing(player)
    end
    player.action = TableLogic.GetCardCheck(player.handCards, player.cardsCombo, getCards[#getCards])
    --]]

    ---[[
    --未听牌时检测手牌。 策划又修改成听牌只能胡不能吃碰杠
    if #player.tingCards==0 then 
        player.action = TableLogic.GetCardCheck(player.handCards, player.cardsCombo, getCards[#getCards])
        --log.info("GetCard player.action=", player.action)
        --log.info("player.tingCards=", player.tingCards)

        --检测他是否听牌
        LocalGame.CheckTing(player)
    else
        --听牌时能胡
        local isHu = false
        for _, v in pairs(player.tingCards) do
            if getCards[#getCards]==v then 
                isHu = true
                break
            end
        end
        if isHu==true then 
            local oneAction = TableLogic.FillOneAction(def.operType.zimo, {getCards[#getCards]})
            table.insert(player.action, oneAction)
        end
    end
    --]]

    if #player.action~=0 then 
        LocalGame.PlayerCanOper(player.seat_id)
    else
        LocalGame.PlayerNeedOutCard(player.seat_id)
    end
end

--玩家无特殊操作只能选择打一张牌
function LocalGame.PlayerNeedOutCard(seat_id)
    local player = LocalGame.seatList[seat_id]
    if not player then 
        return
    end

    log.debug("player=", player)

    local notify = {}
    notify.time_out = def.stateTime[LocalGame.curState] - LocalGame.checkTime
    notify.combo = {
        {
            oper_type = def.operType.outCard,
            cards = TableLogic.GetBestOutCard(player.handCards, player.tingCards, player.getCards[#player.getCards]),
            oper_seat_id = def.maxValue,
        }
    }
    notify.oper_type = {def.operType.outCard}

    --操作插入
    LocalGame.FillTheTurnPlayers(player.seat_id, def.operType.outCard, notify.combo.cards, notify.combo.oper_seat_id)
    player.action = { {oper_type=def.operType.outCard, oper_cards={notify.combo.cards}} }
    
    if player.isRobot==true then 
        --log.info("111111111   player.canTingCards=", player.canTingCards)
        if #player.canTingCards~=0 then 
            robot.ting(player.seat_id, LocalGame.OperReq, player.canTingCards[math.random(1, #player.canTingCards)].out_card)
        else
            robot.needOutcard(LocalGame.OperReq, player.seat_id, player.handCards, player.tingCards, player.getCards[#player.getCards], LocalGame.playerHuCards)
        end
    else
        log.info("player:"..player.seat_id.." PlayerNeedOutCard=", notify)
        LocalGame.sendclient_message(player.player_id, {can_oper_notify = notify } )
    end
end

function LocalGame.PlayerCanOper(seat_id, provider)
    local player = LocalGame.seatList[seat_id]
    if not player then 
        return
    end

    --插入check
    local checkAction = TableLogic.FillOneAction(def.operType.check, {})
    table.insert(player.action, checkAction)

    local notify = {}
    notify.time_out = def.stateTime[LocalGame.curState] - LocalGame.checkTime
    notify.combo = {}
    notify.oper_type = {}
    for _, v in pairs(player.action) do
        local oneAction = {}
        oneAction.oper_type = v.oper_type
        oneAction.cards = v.oper_cards
        oneAction.oper_seat_id = provider or def.maxValue
        table.insert(notify.combo, oneAction)
        table.insert(notify.oper_type, v.oper_type)
        LocalGame.FillTheTurnPlayers(player.seat_id, v.oper_type, v.oper_cards, oneAction.oper_seat_id)
    end

    if player.isRobot==true then 
        --log.info("2222222222222  player.canTingCards=", player.canTingCards)
        if #player.canTingCards~=0 then 
            robot.ting(player.seat_id, LocalGame.OperReq, player.canTingCards[math.random(1, #player.canTingCards)].out_card)
        else
            robot.canOper(LocalGame.OperReq, player.seat_id, player.handCards, notify.combo, player.tingCards, player.getCards[#player.getCards])
        end
    else
        log.info("player:"..player.seat_id.." PlayerCanOper=", notify)
        LocalGame.sendclient_message(player.player_id, {can_oper_notify = notify } )
    end
end

function LocalGame.LogOperReq(operArgs, hasConfirm, handCards)
    if hasConfirm==nil then 
        hasConfirm=false
    end
    local confirm = {
        [false] = "[玩家初步确认操作]",
        [true] = "[系统判定确认操作]",
    }

    local operCardString = ""
    for _, v in pairs(operArgs.oper_cards) do
        operCardString = operCardString.." "..v
    end

    log.info(confirm[hasConfirm].."--->Player["..operArgs.seat_id.."] 请求["..def.operName[operArgs.oper_type].."] 操作的牌为["..operCardString.."] 当前手牌为", handCards)
end

function LocalGame.LogOperRes(seatId, operType, operCards, handCards)
    log.info("operCards=", operCards)
    local operCardString = ""
    for _, v in pairs(operCards) do
        operCardString = operCardString.." "..v
    end

    log.info("Player["..seatId.."] 操作成功["..def.operName[operType].."] 操作的牌为["..operCardString.."] 当前手牌为", handCards)
end

--检测是否轮到我操作
function LocalGame.CheckIsMyTurn(player_id)
    local iRet = false

   log.debug("LocalGame.theTurnPlayers=", LocalGame.theTurnPlayers)
    for k, v in pairs(LocalGame.theTurnPlayers) do
        if k==player_id then 
            iRet = true
            break
        end
    end

    return iRet
end

--玩家操作 args为操作参数， hasConfirm为多响时系统确认后发送的确认操作
function LocalGame.OperReq(args, hasConfirm)
    log.info("OperReq args=", args)
    if args.seat_id==0 then 
        args.seat_id = 2
    end
    local player = LocalGame.seatList[args.seat_id]
    log.debug("player=", player)
    if not player then 
        log.debug("11111111111111")
        return
    end

    --检测是否轮到我
    if LocalGame.CheckIsMyTurn(player.seat_id)==false then 
        log.debug("2222222222")
        return
    end

    --补花期间不允许操作(补花有延时)
    if LocalGame.isNowBuhua==true  then 
        log.debug("3333333333333333")
        return
    end

    LocalGame.LogOperReq(args, hasConfirm, player.handCards)
    if args.oper_type == def.operType.outCard then 
        LocalGame.PlayerOutCard(player, args.oper_cards)
    elseif args.oper_type == def.operType.chi then
        LocalGame.PlayerChi(player, args.oper_cards, hasConfirm)
    elseif args.oper_type == def.operType.peng then
        LocalGame.PlayerPeng(player, args.oper_cards, hasConfirm)
    elseif args.oper_type == def.operType.mingGang then
        LocalGame.PlayerMingGang(player, args.oper_cards, hasConfirm)
    elseif args.oper_type == def.operType.anGang then
        LocalGame.PlayerAnGang(player, args.oper_cards)
    elseif args.oper_type == def.operType.buGang then
        LocalGame.PlayerBuGang(player, args.oper_cards)
    elseif args.oper_type == def.operType.zimo then
        LocalGame.PlayerZimo(player, args.oper_cards)
    elseif args.oper_type == def.operType.dianPao then
        LocalGame.PlayerDianPao(player, args.oper_cards, hasConfirm)
    elseif args.oper_type == def.operType.ting then
        LocalGame.PlayerTing(player, args.oper_cards)
    elseif args.oper_type == def.operType.check then
        LocalGame.PlayerCheck(player, args.oper_cards,hasConfirm)
    end
end

function LocalGame.OperRes(ret, seat_id, oper_type, oper_cards, provider)
    local player = LocalGame.seatList[seat_id]
    if not player then 
        return
    end

    local notify = {}
    notify.ret = ret
    notify.seat_id = seat_id
    notify.oper_cards = {oper_type=oper_type, cards=oper_cards, oper_seat_id=provider}

    LocalGame.LogOperRes(seat_id, oper_type, oper_cards, player.handCards)
    LocalGame.broadcast_message( {oper_res = notify } )
end

function LocalGame.CheckTing(player)
    --已经在听牌了就不发听消息了
    if #player.tingCards~=0 then 
        return
    end

    --能胡就不听牌检测了
    local canHu = false
    for _, v in pairs(player.action) do
        if v.oper_type==def.operType.zimo then 
            canHu = true
            --return
        end
    end

    --牌桌上的牌和自己手牌统计一下，用来算听的个数
    local allSeeCards = {}
    for _, v in pairs(LocalGame.seatList) do
        --每个玩家打在牌桌上的牌
        for _, card in pairs(v.outCards) do
            --被吃碰杠的牌这里记为负值
            if card>0 then 
                table.insert(allSeeCards, card)
            end
        end
        --每个玩家牌组合里的牌
        for _, oneCombo in pairs(v.cardsCombo) do
            --玩家自己记录自己所有成组的牌
            if v.player_id==player.player_id then 
                for _, card in pairs(oneCombo.oper_cards) do
                    table.insert(allSeeCards, card)
                end 
            else
                --非玩家自己不记录他们暗杠的牌
                if oneCombo.oper_type~=def.operType.anGang then 
                    for _, card in pairs(oneCombo.oper_cards) do
                        table.insert(allSeeCards, card)
                    end 
                end
            end
        end
    end
    --再将自己手牌记录
    for card, cardValue in pairs(player.handCards) do
        if cardValue>0 then 
            for i=1, cardValue do
                table.insert(allSeeCards, card)
            end
        end
    end

    local specFan = {}
    LocalGame.CalcSpecFan(player.seat_id, specFan)
    local tingCards = TableLogic.CheckTing(player.handCards, allSeeCards, player.cardsCombo, specFan)
    
    if #tingCards>0 then 
        player.canTingCards = tingCards
        player.isTing = def.tingStatus.showTing
        local notify = {}
        notify.ting_combo = tingCards
        --log.info("CheckTing=", notify)
        LocalGame.sendclient_message(player.player_id, {can_ting_notify = notify})
    end
end

function LocalGame.UpdatePlayerTingData(player, operCard)
    --取消听打完就置为无状态
    if player.isTing==def.tingStatus.cancelTing then 
        player.isTing=def.tingStatus.nothing
    end

    --待听打牌就变成听状态，组播一下
    if player.isTing==def.tingStatus.waitTing and #player.tingCards==0 then 
        player.tingCards = TableLogic.OutCardCheckTing(player.handCards)
        for _, v in pairs(player.canTingCards) do
            if v.out_card==operCard then 
                player.tingInfo = v.ting_cards
                break
            end
        end
        --log.info("canTingCards", player.canTingCards)
        --log.info("tingInfo", player.tingInfo)
        player.canTingCards = {}        --玩家已经开始听牌了，这里就清了,断线时客户端要判断
        player.isTing=def.tingStatus.ting

        --玩家打出第一张牌时确认了听牌就是天听
        --策划设计文档有误，目前的名词听是指， 打出XX牌后，再凑某张牌后，该组牌可以胡牌，该动作叫听
        --但是他又设计的闲家天听，是指，目前需要凑某张牌后即可胡牌。 这两个听含义并不是一个东西。 
        if #player.outCards==1 and #player.cardsCombo==0 then 
            player.isTianTing = true
        end

        for _, v in pairs(LocalGame.seatList) do
            local notify = {}
            notify.seat_id = player.seat_id
            if v.seat_id==player.seat_id then 
                notify.ting_cards = player.tingInfo
            end
            log.info("UpdatePlayerTingData=", notify)
            LocalGame.sendclient_message(v.player_id, {send_ting_notify = notify } )
        end
    end
end

--打
function LocalGame.PlayerOutCard(player, operCards)
    --玩家打牌检测合法性
    if TableLogic.CheckOutCard(player.handCards, operCards)==true then 
        local turnNext = true

        LocalGame.lastOutCard = operCards[1]
        LocalGame.lastOutCardUser = player.seat_id
        table.insert(player.outCards, operCards[1])

        --操作返回组播
        LocalGame.OperRes(0, player.seat_id, def.operType.outCard, operCards)

        --摸牌检测前和打牌操作后操作数据服务
        LocalGame.EveryTurnReset(true)

        --更新听牌玩家听的数据
        LocalGame.UpdatePlayerTingData(player, operCards[1])

        --记录真实玩家胡的牌,追杀局不给他胡
        if LocalGame.controlMode==-1 and player.isRobot==false then 
            LocalGame.playerHuCards = TableLogic.OutCardCheckTing(player.handCards)
            --log.info("LocalGame.playerHuCards=", LocalGame.playerHuCards)
        end

        --打牌后检测打的这张牌是否触发其他玩家action并转换到下一位或者等待其他人操作
        for _, v in pairs(LocalGame.seatList) do
            if v.seat_id~=player.seat_id then 
                --log.info("1111111111111111operCards=", operCards)
                v.action = TableLogic.OutCardCheck(v.handCards, operCards[1], #v.tingCards)
                if #v.action~=0 then 
                    LocalGame.PlayerCanOper(v.seat_id, player.seat_id)
                    turnNext = false
                end
            end
        end

        --若不需要等别的玩家操作直接转换下一位玩家
        if turnNext==true then 
            LocalGame.TurnOper(true)
        end
    else
        log.info("player=", player)
    end
end

--多玩家响应时玩家操作置为true,并统计目前还未操作玩家个数
function LocalGame.GetNotOperNums(player, operType, operCards)
    local notOper = 0
    for seatId, combos in pairs(LocalGame.theTurnPlayers) do
        if seatId==player.seat_id then 
            combos.confirm_oper = operType
            combos.confirm_oper_cards = operCards
            --玩家操作过了就清掉玩家可操作表 
            player.action = {}
        end

        if combos.confirm_oper==def.maxValue then 
            notOper = notOper + 1
        end
    end

    return notOper 
end

--每回合操作玩家数据填充
function LocalGame.FillTheTurnPlayers(seatId, operType, operCards, operSeat)
    --[[
    theTurnPlayers = {
        [seat_id] = { confirm_oper=xxxx, oper_combos={ {oper_type=xxx, oper_cards=xxx}, {...} } }
    }
    --]]
    local oneOper = {
        oper_type = operType,
        oper_cards = operCards,
        oper_seat_id = operSeat,
    }
    if LocalGame.theTurnPlayers[seatId]==nil then 
        LocalGame.theTurnPlayers[seatId] = {}
        LocalGame.theTurnPlayers[seatId].confirm_oper = def.maxValue
        LocalGame.theTurnPlayers[seatId].confirm_oper_cards = {}
        LocalGame.theTurnPlayers[seatId].oper_combos = {}
    end
    
    table.insert(LocalGame.theTurnPlayers[seatId].oper_combos, oneOper)
end

--确定本次操作成功的数据
function LocalGame.CheckAllOper(player, operType, operCards)
     --检测是否都操作了
     if LocalGame.GetNotOperNums(player, operType, operCards) > 0 then 
        local notify = {}
        notify.ret = def.retMessage.wait
        log.info("CheckAllOper oper_res", notify)
        LocalGame.sendclient_message(player.player_id, {oper_res = notify } )
    else
        local turnSeats = {}
        local actions = {
            [1] = {
                seat_id = def.maxValue,
                oper_type = def.operType.nothing,      
                oper_cards = {},
            }
        }
        --log.info("CheckAllOper LocalGame.theTurnPlayers=", LocalGame.theTurnPlayers)
        --多玩家操作取最大操作权值玩家
        for seatId, combos in pairs(LocalGame.theTurnPlayers) do
            if actions[1].oper_type==def.operType.dianPao then 
                --一炮多响，插入所有胡的玩家
                if combos.confirm_oper==def.operType.dianPao then 
                    local oneAction = {
                        seat_id = seatId,
                        oper_type = combos.confirm_oper,
                        oper_cards = combos.confirm_oper_cards,
                    }
                    table.insert(actions, oneAction)
                    table.insert(turnSeats, seatId)
                end
            else
                --非胡时，只能由操作权值最大的玩家操作
                if combos.confirm_oper>actions[1].oper_type then 
                    actions[1].seat_id = seatId
                    actions[1].oper_type = combos.confirm_oper
                    actions[1].oper_cards = combos.confirm_oper_cards
                    turnSeats[1] = seatId
                end
            end
        end

        --非check和非多响时, 肯定是，吃碰杠 多玩家N选一。本次操作一定是一个玩家，所以先将光标移了，然后玩家准备行动
        if actions[1].oper_type~=def.operType.check and #turnSeats==1 then 
            LocalGame.TurnOper(false, turnSeats)
        end

        --log.info("CheckAllOper actions=", actions)
        --确认了的操作 执行并组播操作信息
        for _, v in pairs(actions) do
            LocalGame.OperReq(v, true)
        end
        --点炮胡结算放在这里，当一炮多响时，延时一下让所有胡玩家都有胡动画后(即胡回应后OperRes)再结算
        if actions[1].oper_type== def.operType.dianPao then 
            --结算
            skynet.timeout(def.stateTime[LocalGame.curState]*100, function()
                LocalGame.Finish(def.operType.dianPao)
            end)
        end
    end
end

--把玩家被吃碰杠拿走的牌变成负值(用来显示箭头的)
function LocalGame.ChangeCardsValue(seat_id)
    local index = #LocalGame.seatList[seat_id].outCards
    LocalGame.seatList[seat_id].outCards[index] = 0 - LocalGame.seatList[seat_id].outCards[index]
end

--吃
function LocalGame.PlayerChi(player, operCards, hasConfirm)
    --玩家初步操作，还没经过服务器计算本次确认操作时
    if hasConfirm~=true then 
        LocalGame.CheckAllOper(player, def.operType.chi, operCards)
    else
        --别人打一张，自己手里用来吃的牌减去2张
        for _, v in pairs(operCards) do
            if v~=LocalGame.lastOutCard then 
                player.handCards[v] = player.handCards[v] - 1
            end
        end
        --插入玩家凑成的组合里
        local oneCombo = {
            oper_type = def.operType.chi,
            oper_cards = operCards,
            oper_seat_id = LocalGame.lastOutCardUser,
        }
        table.insert(player.cardsCombo, oneCombo)

        --被操作的玩家打出的那张牌减掉
        --table.remove(LocalGame.seatList[LocalGame.lastOutCardUser].outCards)
        LocalGame.ChangeCardsValue(LocalGame.lastOutCardUser)

        --操作返回组播
        LocalGame.OperRes(def.retMessage.ok, player.seat_id, def.operType.chi, operCards, oneCombo.oper_seat_id)

        --先复位所有人操作
        LocalGame.EveryTurnReset(true)

        --检测他是否听牌
        if #player.tingCards==0 then 
            LocalGame.CheckTing(player)
        end

        --吃了的玩家必须再打一张牌
        LocalGame.PlayerNeedOutCard(player.seat_id)
    end
end

--碰
function LocalGame.PlayerPeng(player, operCards, hasConfirm)
    --玩家初步操作，还没经过服务器计算本次确认操作时
    if hasConfirm~=true then 
        LocalGame.CheckAllOper(player, def.operType.peng, operCards)
    else
        --别人打一张，自己手里用来碰的牌减去2张
        player.handCards[operCards[1]] = player.handCards[operCards[1]] - 2
        --插入玩家凑成的组合里
        local oneCombo = {
            oper_type = def.operType.peng,
            oper_cards = operCards,
            oper_seat_id = LocalGame.lastOutCardUser,
        }
        table.insert(player.cardsCombo, oneCombo)

        --被操作的玩家打出的那张牌减掉
        --table.remove(LocalGame.seatList[LocalGame.lastOutCardUser].outCards)
        LocalGame.ChangeCardsValue(LocalGame.lastOutCardUser)

        --操作返回组播
        LocalGame.OperRes(0, player.seat_id, def.operType.peng, operCards, oneCombo.oper_seat_id)

        --先复位所有人操作
        LocalGame.EveryTurnReset(true)

        --检测他是否听牌
        if #player.tingCards==0 then 
            LocalGame.CheckTing(player)
        end

        --碰了的玩家再打一张牌
        LocalGame.PlayerNeedOutCard(player.seat_id)
    end
end

--明杠
function LocalGame.PlayerMingGang(player, operCards, hasConfirm)
    --玩家初步操作，还没经过服务器计算本次确认操作时
    if hasConfirm~=true then 
        LocalGame.CheckAllOper(player, def.operType.mingGang, operCards)
    else
        --别人打一张，自己手里用来杠的牌减去3张
        player.handCards[operCards[1]] = player.handCards[operCards[1]] - 3
        --插入玩家凑成的组合里
        local oneCombo = {
            oper_type = def.operType.mingGang,
            oper_cards = operCards,
            oper_seat_id = LocalGame.lastOutCardUser,
        }
        table.insert(player.cardsCombo, oneCombo)

        player.isGang = true

        --操作返回组播
        LocalGame.OperRes(0, player.seat_id, def.operType.mingGang, operCards, oneCombo.oper_seat_id)

        --杠了的玩家再摸一张牌
        LocalGame.GetCard()
    end
end

--暗杠
function LocalGame.PlayerAnGang(player, operCards)
    --自己手里用来杠的牌减去4张
    player.handCards[operCards[1]] = player.handCards[operCards[1]] - 4
    --插入玩家凑成的组合里
    local oneCombo = {
        oper_type = def.operType.anGang,
        oper_cards = operCards,
        oper_seat_id = def.maxValue,
    }
    table.insert(player.cardsCombo, oneCombo)

    player.isGang = true

    --操作返回组播
    LocalGame.OperRes(0, player.seat_id, def.operType.anGang, operCards, oneCombo.oper_seat_id)

    --杠了的玩家再摸一张牌
    LocalGame.GetCard()
end

--补杠
function LocalGame.PlayerBuGang(player, operCards)
    --已经碰了3张， 自己摸到1张补进去的杠牌
    player.handCards[operCards[1]] = player.handCards[operCards[1]] - 1

    local provider
    --插入玩家凑成的组合里
    for _, v in pairs(player.cardsCombo) do
        if v.oper_type==def.operType.peng and v.oper_cards[1]==operCards[1] then 
            v.oper_type = def.operType.buGang
            table.insert(v.oper_cards, operCards[1])
            operCards = v.oper_cards
            provider = v.oper_seat_id
            break
        end
    end

    player.isGang = true

    --操作返回组播
    LocalGame.OperRes(0, player.seat_id, def.operType.buGang, operCards, provider)

    --杠了的玩家再摸一张牌
    LocalGame.GetCard()
end

--自摸胡
function LocalGame.PlayerZimo(player, operCards)
    --操作返回组播
    LocalGame.OperRes(0, player.seat_id, def.operType.zimo, operCards, def.maxValue)
    
    player.huInfo.isHu = true
    player.huInfo.oneHuInfo.huCard = operCards[1]

    --结算
    LocalGame.curState = def.state.finish
    skynet.timeout(def.stateTime[LocalGame.curState]*100, function()
        LocalGame.Finish(def.operType.zimo)
    end)
end

--点炮胡
function LocalGame.PlayerDianPao(player, operCards, hasConfirm)
    if LocalGame.curState==def.state.finish then 
        return
    end

    --玩家初步操作，还没经过服务器计算本次确认操作时
    if hasConfirm~=true then 
        LocalGame.CheckAllOper(player, def.operType.dianPao, operCards)
    else
        LocalGame.curState = def.state.finish
        --被操作的玩家打出的那张牌减掉
        --table.remove(LocalGame.seatList[LocalGame.lastOutCardUser].outCards)
        LocalGame.ChangeCardsValue(LocalGame.lastOutCardUser)
        
        --把胡的牌加入到手里
        player.handCards[operCards[1]] = player.handCards[operCards[1]] + 1

        --操作返回组播
        LocalGame.OperRes(0, player.seat_id, def.operType.dianPao, operCards, LocalGame.lastOutCardUser)

        player.huInfo.isHu = true
        player.huInfo.oneHuInfo.dianPaoRen = LocalGame.lastOutCardUser
        player.huInfo.oneHuInfo.huCard = operCards[1]
    end
end

--听
function LocalGame.PlayerTing(player, operCards)
    player.isTing = def.tingStatus.waitTing

    local notify = {}
    notify.ret = def.retMessage.ok
    notify.seat_id = player.seat_id
    notify.oper_cards = {oper_type=def.operType.ting, cards={}}
    --log.info("PlayerTing=", notify)
    LocalGame.sendclient_message(player.player_id, {oper_res = notify } )
end

--过
function LocalGame.PlayerCheck(player, operCards, hasConfirm)
    --玩家初步操作，还没经过服务器计算本次确认操作时
    if hasConfirm==false then 
        LocalGame.CheckAllOper(player, def.operType.check, {})
    else
        local notify = {}
        notify.ret = def.retMessage.ok
        notify.seat_id = player.seat_id
        notify.oper_cards = {oper_type=def.operType.check, cards={}}
        log.info("PlayerCheck=", notify)
        LocalGame.sendclient_message(player.player_id, {oper_res = notify } )

        --若点击过的时候当前玩家是自己，那么就是摸牌过还要继续打牌
        if LocalGame.curPlayer==player.seat_id then 
            if player.isTing==def.tingStatus.showTing then 
                player.isTing = def.tingStatus.nothing
            end 
            --判断是否要取消待听
            if player.isTing==def.tingStatus.waitTing then 
                player.isTing = def.tingStatus.cancelTing
            end
            --先复位所有人操作
            LocalGame.EveryTurnReset(true)
            LocalGame.PlayerNeedOutCard(player.seat_id)    
        else
        --当前玩家非自己，过后就正常计算下一位玩家
            LocalGame.TurnOper(true)
        end
    end
end

function LocalGame.FillPlayerCombos(cardsCombo)
    local combos = {}
    for _, v in pairs(cardsCombo) do
        local oneInfo = {}
        oneInfo.oper_type = v.oper_type
        oneInfo.cards = v.oper_cards
        oneInfo.oper_seat_id = v.oper_seat_id
        table.insert(combos, oneInfo)
    end
    return combos
end

function LocalGame.GetAllPlayerCombos()
    local player_combos = {}
    for _, v in pairs(LocalGame.seatList) do
        local info = {}
        info.seat_id = v.seat_id
        info.combos = LocalGame.FillPlayerCombos(v.cardsCombo)
        info.outCards = v.outCards
        info.huaPai = v.huaPai
        table.insert(player_combos, info)
    end                                                                           

    return player_combos
end

--
function LocalGame.SortCards(handCards, huCard)
    local temp
    --胡的牌放到最后的位置
    if huCard~=nil and huCard~=def.maxValue then
        for k, v in pairs(handCards) do
            if v==huCard then
                --handCards[k], handCards[#handCards] = handCards[#handCards], handCards[k]
                temp = v
                table.remove(handCards, k)
                break
            end
        end
    end

    table.sort(handCards, function(a,b) return a<b end)
    
    if temp~=nil then 
        table.insert(handCards, temp)
    end
    
    return handCards
end

function LocalGame.FillPlayerFinish()
    if LocalGame.curState~=def.state.finish then
        return
    end

    local player_finish_info = {}
    for _, v in pairs(LocalGame.seatList) do
        local info = {}
        info.seat_id = v.seat_id
        info.cards = LocalGame.SortCards(TableLogic.IndexToCard(v.handCards), v.huInfo.oneHuInfo.huCard)
        info.fanxing = v.fanxing
        info.fanxingValue = v.fanxingValue
        info.combos = LocalGame.FillPlayerCombos(v.cardsCombo)
        table.insert(player_finish_info, info)
    end

    return player_finish_info
end

function LocalGame.GetDeskPai()
    local allSeeCards = {}
    for _, v in pairs(LocalGame.seatList) do
        --每个玩家打在牌桌上的牌
        for _, card in pairs(v.outCards) do
            --被吃碰杠的牌这里记为负值
            if card>0 then 
                table.insert(allSeeCards, card)
            end
        end
        --每个玩家牌组合里的牌
        for _, oneCombo in pairs(v.cardsCombo) do
            if oneCombo.oper_type~=def.operType.anGang then 
                for _, card in pairs(oneCombo.oper_cards) do
                    table.insert(allSeeCards, card)
                end 
            end
        end
    end
    return allSeeCards
end

--一些需要用到游戏数据不好计算的番在这里计算
function LocalGame.CalcSpecFan(seatId, fanxing)
    local thePlayer = LocalGame.seatList[seatId]
    local bankPlayer = LocalGame.seatList[LocalGame.bankuser]

    --天胡，自己是庄家并且一张牌未打时，自摸
    if #bankPlayer.outCards==0 and bankPlayer.seat_id==thePlayer.seat_id and #bankPlayer.cardsCombo==0 then 
        table.insert(fanxing, def.fanXing.tianHe)
    end
    --地人胡
    if #bankPlayer.outCards==1 and bankPlayer.seat_id~=thePlayer.seat_id then 
        if #thePlayer.cardsCombo==0 then 
            --地胡，庄家打出牌只有1张时闲家自摸
            if thePlayer.huInfo.oneHuInfo.dianPaoRen==def.maxValue then 
                table.insert(fanxing, def.fanXing.diHe)
            else
            --人和，庄家打出牌只有1张时闲家点炮
                table.insert(fanxing, def.fanXing.renHe)
            end
        end
    end
    --天听
    if thePlayer.isTianTing==true then 
        table.insert(fanxing, def.fanXing.tianTing)
    end
    --最后一张牌时
    if LocalGame.leftCards==0 then
        --妙手
        if thePlayer.huInfo.oneHuInfo.dianPaoRen==def.maxValue then 
            table.insert(fanxing, def.fanXing.miaoshou)
        else
        --海底炮
            table.insert(fanxing, def.fanXing.haidi)
        end
    end
    --杠花
    if thePlayer.huInfo.oneHuInfo.dianPaoRen==def.maxValue and thePlayer.isGang==true then 
        table.insert(fanxing, def.fanXing.gangHua)
    end
    --全求人
    if TableLogic.CheckQuanQiuRen(thePlayer.handCards, thePlayer.cardsCombo, thePlayer.huInfo.oneHuInfo.huCard, thePlayer.huInfo.oneHuInfo.dianPaoRen)==true then 
        table.insert(fanxing, def.fanXing.quanQiuRen)
    end
    --不求人
    if TableLogic.CheckBuQiuRen(thePlayer.cardsCombo, thePlayer.huInfo.oneHuInfo.dianPaoRen)==true then 
        table.insert(fanxing, def.fanXing.buQiuRen)
    end
    --胡绝张
    local allSeeCards = LocalGame.GetDeskPai()
    if TableLogic.CheckHuJueZhang(thePlayer.huInfo.oneHuInfo.huCard, allSeeCards)==true then 
        table.insert(fanxing, def.fanXing.heJueZhang)
    end
    --门清 
    if TableLogic.CheckMenQianQing(thePlayer.cardsCombo, thePlayer.huInfo.oneHuInfo.dianPaoRen)==true then 
        table.insert(fanxing, def.fanXing.menqiangQing)
        --门清听了就是立直
        if thePlayer.isTing==def.tingStatus.ting then 
            table.insert(fanxing, def.fanXing.liZhi)
        end
    end
    --圈风刻
    if TableLogic.CheckQuanFengKe(thePlayer.handCards, thePlayer.cardsCombo)==true then 
        table.insert(fanxing, def.fanXing.quanFengKe)
    end
    --门风刻
    if TableLogic.CheckMenFengKe(thePlayer.handCards, thePlayer.cardsCombo)==true then 
        table.insert(fanxing, def.fanXing.menFengKe)
    end
    --平和
    if TableLogic.CheckPingHu(thePlayer.handCards, thePlayer.cardsCombo)==true then 
        table.insert(fanxing, def.fanXing.pingHe)
    end
    --二五八将
    if TableLogic.CheckEwbj(thePlayer.handCards)==true then 
        table.insert(fanxing, def.fanXing.ewbj)
    end
    --幺九头
    if TableLogic.CheckEwbj(thePlayer.handCards)==true then 
        table.insert(fanxing, def.fanXing.yaoJiuTou)
    end
    --边张
    if TableLogic.CheckBianZhang(thePlayer.handCards, thePlayer.huInfo.oneHuInfo.huCard)==true then 
        table.insert(fanxing, def.fanXing.bianZhang)
    end
    --坎张
    if TableLogic.CheckKanZhang(thePlayer.handCards, thePlayer.huInfo.oneHuInfo.huCard)==true then 
        table.insert(fanxing, def.fanXing.kanZhang)
    end
    --报听
    if thePlayer.isTing==def.tingStatus.ting then 
        table.insert(fanxing, def.fanXing.baoTing)
    end
    --单调将
    if TableLogic.CheckDanDiaoJiang(thePlayer.handCards, thePlayer.huInfo.oneHuInfo.huCard)==true then 
        table.insert(fanxing, def.fanXing.danDiaoJiang)
    end
    --自摸
    if thePlayer.huInfo.oneHuInfo.dianPaoRen==def.maxValue then 
        table.insert(fanxing, def.fanXing.ziMo)
    end
    --花牌
    if #thePlayer.huaPai~=0 then 
        table.insert(fanxing, def.fanXing.huaPai)
    end
end

function LocalGame.CalcScore()
    for _, v in pairs(LocalGame.seatList) do
        if v.huInfo.isHu==true then 
            --普通番型
            v.fanxing = TableLogic.CalcFan(v.handCards, v.cardsCombo)
            --一些不好计算的特殊番型
            LocalGame.CalcSpecFan(v.seat_id, v.fanxing)
            --冲突番型检测
            v.fanxing = TableLogic.CheckFanXingClash(v.fanxing)
            --所有番型总值
            v.fanxingValue = TableLogic.CalcFanValueByFan(v.fanxing, #v.huaPai)
            local fanNums = TableLogic.CalcFanNumsByFan(v.fanxingValue)

            local getScore = fanNums*LocalGame.roomDiZhu
            local dianPaoRen = v.huInfo.oneHuInfo.dianPaoRen
            if dianPaoRen==def.maxValue then 
                getScore = 2*getScore
            end

            --以小博大规则
            for _, player in pairs(LocalGame.seatList) do
                if getScore>player.gold then 
                    getScore = player.gold
                end
            end
            
            --这一个胡是否点炮(预留血战到底的多个胡)
            if dianPaoRen~=def.maxValue then 
                LocalGame.seatList[dianPaoRen].score = LocalGame.seatList[dianPaoRen].score - getScore
                v.score = v.score + getScore
            else
                for _, thePlayer in pairs(LocalGame.seatList) do
                    if thePlayer.seat_id~=v.seat_id then 
                        thePlayer.score = thePlayer.score - getScore
                        v.score = v.score + getScore
                    end
                end
            end
        end

        if v.score>0 then 
            v.tax = TableLogic.CalcHigh(v.score * LocalGame.taxRate)
            v.score = TableLogic.CalcLow(v.score - v.tax)
        end

        --加上杠的分数
        v.score = v.score + v.gangFen
    end
end

function LocalGame.GetPlayerIden(seatId)
    local iden = ""
    if seatId==LocalGame.bankuser then
        iden = iden.."庄家"
    else
        iden = iden.."闲家"
    end

    return iden
end

function LocalGame.GetPlayerPos(thePos)
    if thePos==nil then 
        thePos = math.random(1, 4)
    end

    local pos = ""
    if thePos==def.pos.east then
        pos = pos.."东"
    elseif thePos==def.pos.west then
        pos = pos.."西"
    elseif thePos==def.pos.south then
        pos = pos.."南"
    elseif thePos==def.pos.north then
        pos = pos.."北"
    end

    return pos
end

function LocalGame.GetHutype(huInfo, theHutype)
    local hutype = ""
    --流局
    if theHutype==0 then 
        hutype = "流局"
        return hutype
    end

    --没胡的玩家
    if huInfo.isHu==false then 
        return hutype
    end

    if huInfo.oneHuInfo.dianPaoRen==def.maxValue then
        hutype = hutype.."自摸"
    else
        hutype = hutype..LocalGame.GetPlayerPos(LocalGame.seatList[huInfo.oneHuInfo.dianPaoRen].pos).."位点炮"
    end

    return hutype
end

function LocalGame.GetHuFan(fanxing, fanxingValue, huaPai)
    if #fanxing==0 then 
        return ""
    end

    local huFan = {}
    local fanNums = TableLogic.CalcFanNumsByFan(fanxingValue)
    huFan[1] = "合计: "..fanNums.."番"
    --huFan[1] = fanNums.."番"
    local detial = ""
    for _, v in pairs(fanxing) do
        if v~=def.fanXing.huaPai then 
            detial = detial..def.fanXingName[v]..def.fanXingValue[v].."番|"
        else
            detial = detial..def.fanXingName[v]..def.fanXingValue[v]*#huaPai.."番|"
        end
    end
    huFan[2] = "详细: "..detial
    --huFan[2] = detial

    return huFan
end

function LocalGame.GetHuaPai(huaPai)
    local hua = ""
    for _, v in pairs(huaPai) do
        hua = hua..def.cardName[v]
    end

    return hua
end

function LocalGame.GetGang(cardsCombo)
    local gang = ""
    for _, v in pairs(cardsCombo) do
        if v.oper_type>=def.operType.mingGang then 
            gang = gang..def.operName[v.oper_type]..def.cardName[v.oper_cards[1]].." "
        end
    end

    return gang
end

function  LocalGame.GetHandCards(handCards, huCard)
    local cards = LocalGame.SortCards(TableLogic.IndexToCard(handCards), huCard)

    local text = ""
    for _, v in pairs(cards) do
        text = text .. def.cardName[v].." "
    end

    return text
end

function  LocalGame.GetJinpai(jinpai)
    local text = ""
    for _, v in pairs(jinpai) do
        text = text .. def.cardName[v].." "
    end

    return text
end 

function  LocalGame.GetJinpai2(cardsCombo)
    local text = ""
    for _, v in pairs(cardsCombo) do
        for _, card in pairs(v.oper_cards) do
            text = text .. def.cardName[card]
        end
        text = text.."|"
    end

    return text
end 

function LocalGame.WriteLog(theHuType)
    local game_log = {
        gameId = LocalGame.gameType or 25, ----游戏类型
        gameGroundNum = LocalGame.roomLevel + LocalGame.gameType * 1000, --游戏等级,如奔驰宝马新手房填写 15001
        gamblingNum = LocalGame.roomCode, --牌局编号
        gamblingType = LocalGame.controlMode, ----控制模式
        joinPlayerNum = 0, --下注的真人数量
        joinRobotNum = 0,   --机器人数量填写0
        startTime = LocalGame.startTime * 1000 , --牌局开始时间
        endTime = os.time() * 1000,     --结束时间
        systemTax = 0,  --系统税,不需要写，赋值为0即可
        darkTax = 0,    --暗税税收,不需要写，赋值为0即可
        list = {},
    }
    local playerNum = 0
    local robotNum = 0
    
    for id, player in pairs(LocalGame.seatList) do
        --有下过注并且不是机器人
        --if player.isRobot==false then 
            --if player.canQuit==false then 
                local insertPlayerId = player.player_id
                if player.isRobot==true then 
                    insertPlayerId = -1
                    robotNum = robotNum + 1
                else
                    playerNum = playerNum + 1
                end

                local huFan = LocalGame.GetHuFan(player.fanxing, player.fanxingValue, player.huaPai)
                local playerList = {
                    gamePlayerId  = insertPlayerId,                          --玩家id
                    tax = player.tax,                                        --玩家税收
                    winOrLossFlow = player.score,                            --玩家总输赢
                    ---[[
                    extral1 = {
                        --身份
                        iden = LocalGame.GetPlayerIden(player.seat_id),
                        --玩家位置 东南西北
                        playerPos = LocalGame.GetPlayerPos(player.pos),
                        --胡牌方式
                        huType = LocalGame.GetHutype(player.huInfo, theHuType),
                        --胡牌番合计
                        huFanTotal = huFan[1],
                        --胡牌番详细
                        huFanDetail = huFan[2],
                        --进牌：玩家游戏开始拿到的手牌
                        --jinPai = LocalGame.GetJinpai(player.jinPai),
                        --策划又把进牌改为了组成的牌型
                        jinPai = LocalGame.GetJinpai2(player.cardsCombo),
                        --手牌
                        handCards = LocalGame.GetHandCards(player.handCards, player.huInfo.oneHuInfo.huCard),
                        --杠
                        gang = LocalGame.GetGang(player.cardsCombo),
                        --花牌
                        huaPai = LocalGame.GetHuaPai(player.huaPai),
                        --胡牌
                        huCard = def.cardName[player.huInfo.oneHuInfo.huCard]
                    },
                    --]]
                    zAntes = 0,
                }
                table.insert(game_log.list, playerList)
            --end
        --end
    end
    game_log.joinPlayerNum = playerNum
    game_log.joinRobotNum = robotNum
    return game_log
end

function LocalGame.Finish(huType)
    LocalGame.CalcScore()

    local player_list = LocalGame.FillPlayerList()
    local player_finish_info = LocalGame.FillPlayerFinish()

    local playerScore = {}
    for _, v in pairs(LocalGame.seatList) do
        if v.isRobot==false then 
            local notify = {}
            notify.player_list = player_list
            notify.player_finish_info = player_finish_info
            notify.huType = huType      
            log.info("game_conclude_notify=", notify)
            LocalGame.broadcast_message({ game_conclude_notify = notify })

            --LocalGame.sendclient_message(v.player_id, {game_conclude_notify=notify})

            --匹配场输赢为0也要放进去
            playerScore[v.player_id] = {score=v.score, card_id={}, tax=v.tax}
        end
    end

    --local _ok, _data = pcall(cjson.encode, LocalGame.paiju)
    --[[
    local paiju_notify = {}
    paiju_notify.paiju = _data
    player_pool.broadcast_message({send_paiju_res=paiju_notify})
    log.info("send_paiju_res=", paiju_notify)
    --]]
    --[[
    local file = io.open("paiju.txt", "w+")
    if file==nil then 
        return
    end
    file:write(_data)
    file:close()
    --]]

    ---[[
    local logData = LocalGame.WriteLog(huType)
    --log.info("logData=", logData)
    --log.info("playerScore=", playerScore)
    --skynet.call(LocalGame.roomSrv, 'lua', 'game_conclude_score', LocalGame.tableId, playerScore)
    --skynet.call(LocalGame.roomSrv, 'lua', 'game_conclude_data', LocalGame.tableId, playerScore, logData)
    --skynet.call(LocalGame.roomSrv, 'lua', 'game_end', LocalGame.tableId)
    --]]

    LocalGame.canQuit = true
   
end

--听牌自动摸打
function LocalGame.CheckTingPaiOut()
    if LocalGame.checkTime < 2 then
        return
    end

    --听牌玩家操作自动摸打
    --log.info("LocalGame.theTurnPlayers=", LocalGame.theTurnPlayers)
    for k, v in pairs(LocalGame.theTurnPlayers) do
        local player = LocalGame.seatList[k]
        if player~=nil then 
            if #player.tingCards~=0 then 
                local args = {}
                args.seat_id = player.seat_id
                args.oper_type = def.operType.outCard
                args.oper_cards = TableLogic.GetBestOutCard(player.handCards, player.tingCards, player.getCards[#player.getCards])
                for _, oneAction in pairs(player.action) do
                    --胡牌就胡
                    if oneAction.oper_type==def.operType.zimo or oneAction.oper_type==def.operType.dianPao then 
                        args.oper_type = oneAction.oper_type
                        args.oper_cards = oneAction.oper_cards
                    end
                    --杠牌等他操作
                    if oneAction.oper_type>=def.operType.mingGang and oneAction.oper_type<=def.operType.buGang then 
                        return
                    end
                end
                LocalGame.OperReq(args)
                --已经操作过了复位一下
                LocalGame.checkTime = 0
            end
        end
    end
end

--组装一下，发消息的同时插入牌局记录
function LocalGame.sendclient_message(player_id, msg)
    local msgName
    local msgDetial
    for k, v in pairs(msg) do
        msgName = k
        msgDetial = v
    end

    --player_pool.sendclient_message(player_id, {[msgBody] = msgDetial})
    --修改为如下
    --log.info("LocalGame.playerList=", LocalGame.playerList)
    --log.info("player_id=", player_id)
    if LocalGame.playerList[player_id].agentFd then 
        skynet.send(LocalGame.playerList[player_id].agentFd, "lua", "send_msg", msg, 225)
    end

    if LocalGame.playerList[player_id].isRobot==false then 
        LocalGame.InsertMessage(msgName, msgDetial)
    end
end

function LocalGame.broadcast_message(msg)
    local msgName
    local msgDetial
    for k, v in pairs(msg) do
        msgName = k
        msgDetial = v
    end
    --player_pool.broadcast_message({[msgBody] = msgDetial})
    for _, v in pairs(LocalGame.playerList) do
        if v.agentFd then 
            skynet.send(v.agentFd, "lua", "send_msg", msg, 225)
        end
    end
    
    LocalGame.InsertMessage(msgName, msgDetial)
end

--组装一下，发消息的同时插入牌局记录
function LocalGame.sendclient_message2(player_id, msg)
    local msgName
    local msgDetial
    for k, v in pairs(msg) do
        msgName = k
        msgDetial = v
    end

    --player_pool.sendclient_message(player_id, {[msgBody] = msgDetial})
    --修改为如下
    --log.info("LocalGame.playerList=", LocalGame.playerList)
    --log.info("player_id=", player_id)
    if LocalGame.playerList[player_id].agentFd then 
        SendGamePbMsg("send", LocalGame.playerList[player_id].agentFd, {[msgName] = msgDetial}, 225)
    end

    if LocalGame.playerList[player_id].isRobot==false then 
        LocalGame.InsertMessage(msgName, msgDetial)
    end
end

function LocalGame.broadcast_message2(msg)
    local msgName
    local msgDetial
    for k, v in pairs(msg) do
        msgName = k
        msgDetial = v
    end
    --player_pool.broadcast_message({[msgBody] = msgDetial})
    for _, v in pairs(LocalGame.playerList) do
        if v.agentFd then 
            SendGamePbMsg("send", v.agentFd, {[msgName] = msgDetial}, 225)
        end
    end
    
    LocalGame.InsertMessage(msgName, msgDetial)
end

--牌局回放功能
function LocalGame.InsertMessage(msgBody, msgDetial)
    local index = {}
    index.msgBody = msgBody
    index.msgDetial = msgDetial
    table.insert(LocalGame.paiju, index)
end

------------------------------------------------
--定时触发类任务,每秒检测一次
function LocalGame.TimerFork()
    while true do
        if LocalGame.curState==def.state.gaming then 
            LocalGame.checkTime = LocalGame.checkTime + 1

            LocalGame.CheckTingPaiOut()

            --能胡就胡，不能胡就打最优牌
            --log.info("LocalGame.checkTime=", LocalGame.checkTime)
            if LocalGame.checkTime > def.stateTime[LocalGame.curState] then 
                for seatId, combos in pairs(LocalGame.theTurnPlayers) do
                    if combos.confirm_oper==def.maxValue then 
                        local player = LocalGame.seatList[seatId]
                        if player then 
                            local args = {}
                            args.seat_id = player.seat_id
                            args.oper_type = def.operType.outCard
                            args.oper_cards = TableLogic.GetBestOutCard(player.handCards, player.tingCards, player.getCards[#player.getCards])
                            if player.isTing==def.tingStatus.waitTing then 
                                log.info("player.canTingCards=", player.canTingCards)
                                --args.oper_cards = {player.canTingCards[math.random(1, #player.canTingCards)].out_card}
                            end

                            for _, v in pairs(combos.oper_combos) do
                                --过
                                if v.oper_type==def.operType.check then 
                                    args.oper_type = v.oper_type
                                    args.oper_cards = v.oper_cards  
                                end
                                --胡
                                if v.oper_type==def.operType.zimo or v.oper_type==def.operType.dianPao then 
                                    args.oper_type = v.oper_type
                                    args.oper_cards = v.oper_cards   
                                    break
                                end
                            end
                            log.info("TimerForkDo args=", args)
                            LocalGame.OperReq(args)
                        end
                    end
                end

                --已经操作过了复位一下
                LocalGame.checkTime = 0
            end
        end 
        skynet.sleep(100)
    end
end

function LocalGame.Test()
    --local openTest = true
    local openTest = false 

    if openTest==false then 
        return
    end

    local handCards = {
        11, 11, 11, 
        12, 13, 14,
        13, 14, 15,
        42,
    }
    local destCard = TableLogic.CardToIndex(handCards)

    --local huInfo = TableLogic.CheckTing(destCard)
    local huInfo = TableLogic.CheckHu(destCard, 42)
    log.info("huInfo=", huInfo)

    --TableLogic.GetBestOutCard(destCard, {}, 41, false)
    --local jiuBaoInfo = TableLogic.CheckHuJiubao(destCard)
    --log.info("jiubaoInfo=", jiuBaoInfo)
end

--------------------------------game_process--------------------------------
--由jsys_room.lua文件CMD.start中的select_table调用
function game_process:game_init(args)
    --log.info("game_process:game_init222", args)
    LocalGame.DataInit()

    --初始化数据放在init里
    --LocalGame.roomSrv = args.room_srv  --后续数据上报在game_serivce里处理
    LocalGame.tableId = args.table_id
    LocalGame.gameType = args.game_type or 25
    LocalGame.roomLevel = args.room_level
    LocalGame.roomConfig = args.room_config 
    --LocalGame.ruleConfig = args.rule_config 
    --LocalGame.robotConfig = args.robot_config  
    LocalGame.roomId = args.room_config.room_id 
    LocalGame.roomDiZhu = args.room_config.room_base_note
    LocalGame.taxRate = LocalGame.roomConfig.system_tax or 0
    LocalGame.bounsRate = LocalGame.roomConfig.reward_tax or 0

    --log.info("LocalGame=", LocalGame)
    --一个处理定时触发类任务
    skynet.fork(LocalGame.TimerFork)
end

--在start时创建生命周期和整个服务同步的两个fork
function game_process:game_start(args)
    --[[
    LocalGame.Test()
    --log.info("gamestart args=", args)
    LocalGame.roomSrv = args.room_srv
    LocalGame.tableId = args.table_id
    LocalGame.gameType = args.game_type
    LocalGame.roomLevel = args.room_level
    LocalGame.ruleConfig = args.rule_config 
    LocalGame.roomConfig = args.room_config 
    LocalGame.robotConfig = args.robot_config  
    LocalGame.roomId = args.room_config.room_id 
    LocalGame.roomDiZhu = args.room_config.room_base_note
    LocalGame.controlMode = args.control_mode
    LocalGame.roomCode = args.room_code

    LocalGame.taxRate = LocalGame.roomConfig.system_tax or 0
    LocalGame.bounsRate = LocalGame.roomConfig.reward_tax or 0
    --]]

    LocalGame.gameType = args.game_type or 25
    LocalGame.roomCode = args.roomCode
    LocalGame.controlMode = args.control_mode

    LocalGame.GameStart(args)
    --log.info("game_start LocalGame.seatList=", LocalGame.seatList)
end

function game_process:disconnect(player_id,args)
    log.info("game_process disconnect player_id=", player_id)
    --[[
    local player = LocalGame.playerList[player_id]
    if player==nil then
        return
    end
    player = LocalGame.seatList[player.seat_id]

    --玩家已经点了听但是没打牌断线直接给他打出去并更新听牌数据
    if player~=nil and player.isTing==1 and #player.tingCards==0 and LocalGame.curPlayer==player.seat_id then 
        local args = {}
        args.seat_id = player.seat_id
        args.oper_type = def.operType.outCard
        --args.oper_cards = {player.canTingCards[math.random(1, #player.canTingCards)].out_card}
        --log.info("disconnect tingOut args=", args)
        --这里已经改断线不直接打了
        --LocalGame.OperReq(args)
    end

    --]]
    --log.info("game_process disconnect player_id=", player_id)
end

--玩家退出，要判断该玩家是否能够退出
function game_process.leave_room_req(player_id, args)  
    if not LocalGame.xpcallStatus then
        log.error('state game_process error ')
        LocalGame.playerList[player_id] = nil
        return true
    end
    local user = LocalGame.playerList[player_id]
    if user and not LocalGame.canQuit then
        return false
    end

    LocalGame.playerList[player_id] = nil
    LocalGame.seatList[player.seat_id] = nil

    return true
end

function game_process.inter_error_callback(player_id, cmd)
    LocalGame.playerList = LocalGame.playerList or {}
    local user = LocalGame.playerList[player_id]
    if user then
        user.canQuit = true
    end
end

function LocalGame.GetAllPlayerTingStatus()
    local tingStatus = {}
    for _, v in ipairs(LocalGame.seatList) do
        table.insert(tingStatus, v.isTing)
    end

    return tingStatus
end

function LocalGame.GetAllPlayerHandcards()
    local handCardsNum = {}
    for _, v in ipairs(LocalGame.seatList) do
        local nums = 0
        for _, cards in pairs(v.handCards) do
            if cards>0 then 
                nums = nums + cards
            end
        end
        table.insert(handCardsNum, nums)
    end

    return handCardsNum
end

function game_process.change_fd_test(player_id, fd)
    log.info("11111 LocalGame.playerList[player_id].fd=", LocalGame.playerList[player_id].agentFd)
    LocalGame.playerList[player_id].agentFd = fd
    log.info("222222222 LocalGame.playerList[player_id].fd=", LocalGame.playerList[player_id].agentFd)

end

function game_process:reconnect_game(player_id,args)
    local player = LocalGame.playerList[player_id]
    if not player then
        log.error('reconnect_game user is nil')
        return
    end
    player = LocalGame.seatList[player.seat_id]

    --
    local leftTime = def.stateTime[LocalGame.curState] - LocalGame.checkTime
    if leftTime < 0 then 
        leftTime = 0
    end

    local combos = {}
    combos.combo = {}
    combos.oper_type = {}
    log.info("LocalGame.theTurnPlayers=", LocalGame.theTurnPlayers)
    if LocalGame.theTurnPlayers[player.seat_id]~=nil and LocalGame.theTurnPlayers[player.seat_id].oper_combos~=nil then 
        for _, v in pairs(LocalGame.theTurnPlayers[player.seat_id].oper_combos) do
            local oneAction = {}
            oneAction.oper_type = v.oper_type
            oneAction.cards = v.oper_cards
            oneAction.oper_seat_id = v.oper_seat_id
            table.insert(combos.combo, oneAction)
            table.insert(combos.oper_type, v.oper_type)
        end
    end

    local notify = {}
    notify.my_seat_id = player.seat_id
    notify.oper_seat_id = LocalGame.curPlayer
    notify.bankUser_seat_id = LocalGame.bankuser
    notify.leftTime = leftTime
    notify.room_info = {room_base_note=tostring(LocalGame.roomDiZhu), room_code=LocalGame.roomCode}
    notify.player_list = LocalGame.FillPlayerList()
    notify.player_finish_info = LocalGame.FillPlayerFinish()
    notify.player_ting_cards = player.tingInfo
    notify.player_combos = LocalGame.GetAllPlayerCombos()
    notify.left_card = LocalGame.leftCards
    notify.handCards = TableLogic.IndexToCard(player.handCards)
    notify.combos = combos
    notify.player_handcards_nums = LocalGame.GetAllPlayerHandcards()
    notify.playerTingStatus = LocalGame.GetAllPlayerTingStatus()
    notify.ting_combo = player.canTingCards 
    notify.last_outcard_seat_id = LocalGame.lastOutCardUser
    notify.windPos = player.pos

    log.info("game_reconnect_info=", notify)
    --重连消息不记录到牌局
    LocalGame.sendclient_message(player_id, {game_reconnect_info=notify})
end

--游戏内消息
--玩家请求操作
function game_process:oper_req(agent, args)
    --log.info("oper_req arrgs=", args)
    LocalGame.OperReq(args, false)
    --log.debug("seatList=", LocalGame.seatList)
end


return game_process